package com.hup.utils.commons.thread.component;

import lombok.Setter;

import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 参考资料:
 * 简化版的Tomcat执行器
 *  https://www.jianshu.com/p/98f530bd93b0
 *  org.apache.tomcat.util.threads.ThreadPoolExecutor
 *  org.apache.tomcat.util.threads.TaskQueue
 * JDK和Tomcat中的线程池
 *  https://blog.csdn.net/Holmofy/article/details/81610481
 *
 * @author hugan
 * @date 2020/5/30
 */
class EfficientTaskQueue extends LinkedTransferQueue<Runnable> {
    private static final long serialVersionUID = 1L;

    @Setter
    private transient volatile EfficientExecutor parent;

    /**
     * 智商不够,无法将queueSize的逻辑搬到本类中处理
     */
    protected EfficientTaskQueue(/*int queueSize*/) {
    }

    public boolean force(Runnable o) {
        if (parent.isShutdown()) throw new RejectedExecutionException("taskQueue.notRunning");
        return super.offer(o); //forces the item onto the queue, to be used if the task is rejected
    }

    public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
        if (parent.isShutdown()) throw new RejectedExecutionException("taskQueue.notRunning");
        return super.offer(o, timeout, unit); //forces the item onto the queue, to be used if the task is rejected
    }

    @SuppressWarnings("NullableProblems")
    @Override
    public boolean offer(Runnable o) {
        int poolSize = parent.getPoolSize();//the number of threads

        //线程数达到最大线程数，尝试入队
        //we are maxed out on threads, simply queue the object
        if (poolSize == parent.getMaximumPoolSize()) return super.offer(o);
        //提交的任务数小于线程数，也就是有空余线程，入队让空闲线程取任务
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount() <= poolSize) return super.offer(o);

        //走到这说明线程池没有空闲线程
        //这里返回false，改变了LinkedBlockingQueue默认的行为
        //使得Tomcat可以创建临时线程
        //if we have less threads than maximum force creation of a new thread
        if (poolSize < parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
        return super.offer(o);
    }

}
